#!/usr/bin/env python
# -*- coding: ISO-8859-15 -*-
#
# Copyright (C) 2007 Rafael S. Gonzalez D'Leon <rafaeldleon@gmail.com>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA

import os
import ldap
import ldapurl
from sshproxy.config import get_config

class LDAPDB(object):
    """
    This object is meant to be used as a mixin to open only the
    necessary number of connections to the database.

    It implements the open_db method, that should be called from __reginit__.
    """
    __db = {}
    def open_db(self):
        """
        This method creates one connection with the ldap database.
        """
        cfg = get_config('%s.ldap' % self._db_handler)
        self.base_dn = cfg['base_dn']
        conid = 'ldap://%s:%s/%s??%s??bindname=%s,X-BINDPW=%s' % (cfg['host'], cfg['port'],
                                         self.base_dn, 'sub',
                                         ldapurl.ldapUrlEscape(cfg['user_dn']),
                                         cfg['password'])
        
        if not self.__db.has_key(conid):
            try:
                ldap_url = ldapurl.LDAPUrl(conid)
                openconnection = ldap.initialize(ldap_url.initializeUrl())
                openconnection.simple_bind_s(ldap_url.who,ldap_url.cred)                
                LDAPDB.__db[conid] = openconnection
            except:
                if not os.environ.get('SSHPROXY_WIZARD', None):
                    raise

        self.db = self.__db[conid]

    def ldap_get(self, filtervar, basedn=None):
        """
        This method returns the first element found that matches de filtervar criteria.
        If basedn specified, the original base_dn is modified.
        """
        if basedn == None:
            basedn = self.base_dn
        try:
            bindconnection = self.db
            result = bindconnection.search_s(basedn, ldap.SCOPE_SUBTREE, filtervar)[0]
            #bindconnection.unbind_s()
        except:
            return None
        if not result or not len(result):
            return None
        if len(result) == 1:
            return result
        return result
    
    def ldap_list(self, filtervar, basedn=None):
        """
        This method returns a list of objects in the ldap directory that matches filtervar criteria.
        If basedn specified, the original base_dn is modified.
        """
        if basedn == None:
            basedn = self.base_dn
        try:    
            bindconnection = self.db
            result = bindconnection.search_s(basedn, ldap.SCOPE_SUBTREE, filtervar)
        #bindconnection.unbind_s()
        except:
            return None
            #return []
        if not result or not len(result):
            #return []
            return None
        return result
    
    def ldap_add(self, dnvar, listAttrs):
        """
        This method creates a new entry in ldap with the attributes specified in listAttrs.
        """
        bindconnection = self.db
        try:
            result = bindconnection.add_s(dnvar, listAttrs)
            #bindconnection.unbind_s()
        except:
            raise
            return None
        return result[0]
        
    def ldap_update(self, dnvar, listAttrs):
        """
        This method verifies if an attribute exists in an entry dnvar and if it is the case
        It replaces if it is different or pass if equals.
        """
        
        bindconnection = self.db
        modvarlist = []
	
	for attribute in listAttrs:
            if type(attribute[1]) is list:
                sameattributelist = attribute[1]
            else:
                sameattributelist = [attribute[1]]
                
            for singleattribute in sameattributelist:
	        singleattribute=str(singleattribute)
                try:
		    compare = bindconnection.compare_s(dnvar, attribute[0], singleattribute)
                except ldap.NO_SUCH_ATTRIBUTE:
                    compare = 2
                except:
                    raise
                if compare == 0 and attribute[0] == 'objectClass':
                    tempattr = list((attribute[0],singleattribute))
                    tempattr.insert(0,ldap.MOD_ADD)
                    modvarlist.append(tuple(tempattr))
                elif compare == 0 and attribute[0]!='sshProxyTags':
                    tempattr = list((attribute[0],singleattribute))
                    tempattr.insert(0,ldap.MOD_REPLACE)
                    modvarlist.append(tuple(tempattr))
                elif compare == 2 or (compare == 0 and attribute[0]=='sshProxyTags'):
                    #if attribute[0] == 'sshProxyTags':
                     #    exists = bindconnection.search_s(dnvar,ldap.SCOPE_BASE,'(sshProxyTags=hola*)')
                    tempattr = list((attribute[0],singleattribute))
                    tempattr.insert(0,ldap.MOD_ADD)
                    modvarlist.append(tuple(tempattr))
        try:
            result = bindconnection.modify_s(dnvar,modvarlist)
        except:
            raise #str(modvarlist)
            return None
                        
        return result[0]
    
    def ldap_del_attrs(self,dnvar,listAttrs):
        bindconnection = self.db
        modvarlist = []
        for attribute in listAttrs:
            tempattr = list(attribute)
            tempattr.insert(0,ldap.MOD_DELETE)
            modvarlist.append(tuple(tempattr))
        try:
            result = bindconnection.modify_s(dnvar,modvarlist)
        except:
            return None
        return result[0]
    
    def ldap_del(self, dnvar):
        bindconnection = self.db
        try:
            if bindconnection.compare_s(dnvar,'sshProxyUndeleteable','TRUE'):
                return None
        except:
            pass
        try:
            result = bindconnection.delete_s(dnvar)
            #bindconnection.unbind_s()
        except:
            return None
        return result[0]
